<!DOCTYPE html>
<html lang="en">
	<head>
	  <meta charset="UTF-8">
	  <meta name="viewport" content="width=device-width, initial-scale=1.0">
	  <meta http-equiv="X-UA-Compatible" content="ie=edge">
	  <title>Document</title>
	</head>
	<body>	
		<div class='test_btn'>
		    click
		</div>
		<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
		<script>
			//ES6 之前，不能直接为函数的参数指定默认值
			// function log(x,y){
			// 	if (typeof y === 'undefined') {
  			// 	y = 'World';
			// 	}
			// 	console.log(x,y)
			// }
			// log("hi","");

			//ES6 允许为函数的参数设置默认值，即直接写在参数定义的后面
			// function log(x, y = 'World') {
			//   console.log(x, y);
			// }
			// log('Hello') // Hello World
			// log('Hello', 'China') // Hello China
			// log('Hello', '') // Hello

			//参数变量是默认声明的，所以不能用let或const再次声明
			// function Point(x = 0,y = 0){
			// 	this.x = x;
			// 	this.y = y;
			// 	// let x = 1; // error
  			//	//const x = 2; // error
			// }
			// const p = new Point();
			// console.log(p);

			//使用参数默认值时，函数不能有同名参数
			//不报错
			// function foo(x,x,y){
			// }
			//报错
			// function foo(x,x,y=1){
			// }
			//函数.html:44 Uncaught SyntaxError: Duplicate parameter name not allowed in this context

			//参数p的默认值是x + 1。这时，每次调用函数foo，都会重新计算x + 1，而不是默认p等于 100
			// let x = 99;
			// function foo(p = x + 1){
			// 	console.log(p);
			// }
			// foo();//100
			// x = 100;
			// foo();//101


			// function foo({x,y=1}){
			// 	console.log(x,y)
			// }
			// // foo();//Uncaught TypeError: Cannot destructure property `x` of 'undefined' or 'null'
			// foo({});//undefined 1
			// foo({x:2});//2 1
			// foo({x:1,y:2});//1 2

			//如果没有提供参数，函数foo的参数默认为一个空对象
			// function foo({x,y=5} = {}){
			// 	console.log(x,y);
			// }

			// foo() //undefined 5

			//如果函数fetch的第二个参数是一个对象，就可以为它的三个属性设置默认值。这种写法不能省略第二个参数，如果结合函数参数的默认值，就可以省略第二个参数。这时，就出现了双重默认值
			// function fetch(url,{body = '',method = 'get',headers = {}}){
			// 	console.log(method);
			// }
			// fetch('http://example.com',{});//get
			// fetch('http://example.com');//函数.html:73 Uncaught TypeError: Cannot destructure property `body` of 'undefined' or 'null'

			// function fetch(url,{body = '',method = 'get', headers = {}} = {}){
			// 	console.log(method);
			// }
			// fetch('http://example.com')//get

			//写法一函数参数的默认值是空对象，但是设置了对象解构赋值的默认值；写法二函数参数的默认值是一个有具体属性的对象，但是没有设置对象解构赋值的默认值
			// function m1({x=0,y=0}={}){
			// 	return [x,y];
			// }
			// function m2({x,y}={x:0,y:0}){
			// 	return [x,y];
			// }
			// console.log(m1());//[0,0]
			// console.log(m2());//[0,0]
			// console.log(m1({}));//[0,0]
			// console.log(m2({}));//[undefined,underfine]

			//通常情况下，定义了默认值的参数，应该是函数的尾参数
			// function f(x = 1, y) {
			// 	return [x, y];
			// }
			// console.log(f());// [1, undefined]
			// console.log(f(0));// [0, undefined]
			// console.log(f(,0));//Uncaught SyntaxError: Unexpected token ,
			// console.log(f(undefined,2));//[1, 2]
			// function f(x,y = 5,z){
			// 	return[x,y,z];
			// }
			// console.log(f());//[undefined, 5, undefined]
			// console.log(f(1));//[1, 5, undefined]
			// console.log(f(1,2));//[1, 2, undefined]
			// console.log(f(1,undefined,2));//[1, 5, 2]

			//不省略它后面的参数，除非显式输入undefined null则没有这个效果
			// function foo(x = 5,y = 6){
			// 	console.log(x,y);
			// }
			// foo(undefined,null);//5 null

			//指定了默认值以后，函数的length属性，将返回没有指定默认值的参数个数 length属性的含义是，该函数预期传入的参数个数
			// console.log((function(a){}).length);//1
			// console.log((function(a,b){}).length);//2
			// console.log((function(a,b,c = 3){}).length);//2
			// //如果设置了默认值的参数不是尾参数，那么length属性也不再计入后面的参数了。
			// console.log((function(a,b = 3,c){}).length);//1

			// console.log((function(...args) {}).length);//0 后文的 rest 参数也不会计入length属性

			// var x = 1;
			// function f(x,y=x){
			// 	console.log(y);
			// }
			// f();//undefined
			// f(2)//2

			// let x = 1;
			// function f(y = x) {
			//   let x = 2;
			//   console.log(y);
			// }
			// f() // 1

			// function f(x,y = x) {
			//   console.log(y);
			// }
			// f() //undefined

			// function f(y = x) {
			//   let x = 2;
			//   console.log(y);
			// }
			// f() //Uncaught ReferenceError: x is not defined

			// var x = 1;
			// function foo(x = x) {
			//   console.log(x);
			// }
			// foo() //函数.html:148 Uncaught ReferenceError: x is not defined

			// let foo = 'outer';
			// function bar(func = () => foo){
			// 	let foo = 'inner';
			// 	console.log(func());
			// }
			// bar();//outer

			// function bar(func = () => foo){
			// 	let foo = 'inner';
			// 	console.log(func());
			// }
			// bar();//Uncaught ReferenceError: foo is not defined

			// var x = 1;
			// function foo(x, y = function() { x = 2; }) {
			//   x = 3;
			//   y();
			//   console.log(x);
			// }
			// foo() // 2
			// console.log(x)// 1

			// function throwIfMissing(){
			// 	throw new Error('Missing parameter');
			// }
			// function foo(mustBeProvided  =throwIfMissing()){
			// 	return mustBeProvided;
			// }
			// foo()//Uncaught Error: Missing parameter

			// function foo(optional = undefined) { ··· }//Uncaught SyntaxError: Invalid or unexpected token

			// function add(...values) {
			// 	let sum = 0;
			// 	for (var val of values) {
			// 	sum += val;
			// 	}
			// 	return sum;
			// }
			// console.log(add(2,5,3));//10

			// function sortNumbers() {
   				//	return Array.prototype.slice.call(arguments).sort();
			// }
			// console.log(sortNumbers(3,2,4,5));//[2, 3, 4, 5]
			
			// const sortNumbers = (...numbers) => numbers.sort();
			// console.log(sortNumbers(2,5,4,9));//[2, 4, 5, 9]



			// function push(array, ...items) {
			//     items.forEach(function(item) {
			//     array.push(item);
			//     console.log(item);
			//   });
			// }
			// var a = [];
			// push(a, 1, 2, 3)//1 2 3

			// //rest 参数之后不能再有其他参数（即只能是最后一个参数），否则会报错
			// function f(a, ...b,c) {
			// 	console.log(a, ...b,c);
			// }
			// f(2,4,5,6)//Uncaught SyntaxError: Rest parameter must be last formal parameter

			//函数的length属性，不包括 rest 参数
			// console.log(function(a){}.length)//1
			// console.log(function(a,...b){}.length)//1
			// console.log(function(...a) {}.length)  // 0

			// function doSomething(a,b){
			// 	'use strict';
			// 	console.log(a,b)
			// }
			// doSomething(2,4)

			// function doSomething(a,b = a){
			// 	'use strict';
			// 	console.log(a,b);
			// }
			// doSomething()//Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list


			// const doSomething = function({a,b}){
			// 	'use strict';
			// 	console.log(a,b);
			// }
			// doSomething()//Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list

			// const doSomething = (...a) =>{
			// 	'use strict';
			// 	console.log(...a);
			// };
			// doSomething();//Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list

			// const obj = {
			// 	doSomething({a,b}){
			// 		'use strict';
			// 		console.log(a,b)
			// 	}
			// }//Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list

			// function doSomething(value = 070) {
			//     'use strict';
			//     return value;
			// }
			// doSomething()//Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list

			// 'use strict';
			// function doSomething(a,b = a){
			// 	console.log(a,b);
			// }
			// doSomething(2);//2 2

			// const doSomething = (function () {
			//     'use strict';
			//     return function(value = 42) {
			//      return value;
			//     };
			// }());
			// console.log(doSomething);//ƒ (value = 42) {return value; }


			// function foo(){}
			// console.log(foo.name);//foo

			// var f = function () {};
			// console.log(f.name);//f

			// const bar =  function baz(){};
			// console.log(bar.name);//baz

			// console.log((new Function).name);//anonymous

			// function foo(){}
			// console.log(foo.bind({}).name);// "bound foo"
			// console.log((function(){}).bind({}).name);// "bound "

			// var f = v => v;
			// // 等同于
			// var f = function(v){
			// 	return v;
			// }

			// var f = () => 5;
			// // 等同于
			// var f = function(){
			// 	return 5;
			// }

			// var sum = (num1,num2) =>num1 + num2;
			// // 等同于
			// var sum = function(num1,num2){
			// 	return num1+num2;
			// }

			// var sum = (num1,num2) =>{return num1 + num2;}

			// let getTemItem = id =>{id:id,name:"Temp"};//由于大括号被解释为代码块，所以如果箭头函数直接返回一个对象，必须在对象外面加上括号，否则会报错

			// let getTemItem = id =>({id:id,name:"Temp"});
			// console.log(getTemItem);//id =>({id:id,name:"Temp"})

			// let foo = () => { a: 1 };
			// console.log(foo()); // undefined

			//如果箭头函数只有一行语句，且不需要返回值，可以采用下面的写法，就不用写大括号了
			// let fn = () => void doesNotReturn();

			// const full = ({first,last}) => first + '' + last;
			// // 等同于
			// function full(person){
			// 	return person.first + '' + person.last;
			// }

			// const isEven = n => n % 2 ==0;
			// const square = n => n * n;

			// [1,2,3].map(function(x){
			// 	return x * x;
			// });
			// [1,2,3].map(x => x * x);

			// var result = values.sort(function(a,b){
			// 	return a-b;
			// });
			// var result = values.sort((a,b) =>a-b);

			// const numbers = (...nums) =>nums;
			// console.log(numbers(1,2,3,4,5));//[1, 2, 3, 4, 5]

			// const headAndTail = (head,...tail) =>[head,tail];
			// console.log(headAndTail(1,2,3,4,5));// [1,[2,3,4,5]]

			//函数体内的this对象，就是定义时所在的对象，而不是使用时所在的对象
			// function foo(){
			// 	setTimeout(() => {
			// 		console.log('id:',this.id)
			// 	},1000);
			// }
			// var id = 21;
			// foo.call({id:42});//id: 42

			//Timer函数内部设置了两个定时器，分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域（即Timer函数），后者的this指向运行时所在的作用域（即全局对象）。所以，3100 毫秒之后，timer.s1被更新了 3 次，而timer.s2一次都没更新
			// function Timer() {
			//     this.s1 = 0;
			//     this.s2 = 0;
			//     // 箭头函数
			//     setInterval(() => this.s1++, 1000);
			//     // 普通函数
			//     setInterval(function () {
			//     this.s2++;
			//     }, 1000);
			// }
			// var timer = new Timer();
			// setTimeout(() => console.log('s1: ', timer.s1), 3100);//s1:  3
			// setTimeout(() => console.log('s2: ', timer.s2), 3100);//s2:  0

			// var handler = {
			// 	id:'123456',
			// 	init:function(){
			// 		document.addEventListener('click',event =>this.doSomething(event.type),false);
			// 	},
			// 	doSomething:function(type){
			// 		console.log('handling'+type+ 'for' + this.id);
			// 	}
			// };
			// console.log(handler);//{id: "123456", init: ƒ, doSomething: ƒ}

			// var handler = {
			// 	id:'123456',
			// 	init:function(){
			// 		document.addEventListener('click',function(event){
			// 			return this.doSomething(event.type)
			// 		}
			// 		,false);
			// 	},
			// 	doSomething:function(type){
			// 		console.log('handling'+type+ 'for' + this.id);
			// 	}
			// };
			// console.log(handler);


			/*let dom_btn = document.getElementsByClassName('test_btn')
		    // document.addEventListener('click',function(event){
		    	console.log(this);//document
		    //   return this.doSomething(event.type)
		    // })
		    document.addEventListener('click',event => {
		      console.log(this);//window
		      return this.doSomething(event.type)
		    })
    		function doSomething (event) {
      			console.log(event)
      		}*/

			// function foo(){
			// 	this.id = 100;
			// 	setTimeout(() =>{
			// 		console.log('id',this.id)
			// 	},100)
			// }
			// function foo(){
			// 	this.id=2000
			// 	var _this = this.id;
			// 	setTimeout(()=>{
			// 		console.log("id",_this)
			// 	},100);
			// }
			// foo();

			// function foo(){
			// 	return ()=>{
			// 		return() =>{
			// 			return() =>{
			// 				console.log('id:',this.id);
			// 			};
			// 		};
			// 	};
			// }
			// var f = foo.call({id:1});
			// var t1 = f.call({id:2})()();//id: 1
			// var t2 = f().call({id:3})();//id: 1
			// var t3 = f()().call({id:4});//id: 1

			// function foo() {
			//     setTimeout(() => {
			//     console.log('args:', arguments);
			//   }, 100);
			// }
			// foo(2, 4, 6, 8)//args: Arguments(4) [2, 4, 6, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]

			//箭头函数没有自己的this，所以bind方法无效，内部的this指向外部的this
			// console.log((function(){
			// 	return [
			// 	(()=>this.x).bind({x:'inner'})()];
			// }).call({x:'outer'}));//["outer"]


			//不适合用箭头函数的两种情景
			//一、定义函数的方法，且该方法内部包含this;
			//二、需要动态this时，另外函数体很复杂，有许多行，或者函数内部有大量的读写操作，不单纯是为了计算值，这时也不应该使用箭头函数，而是要使用普通函数

			//箭头函数内部，还可以再使用箭头函数
			// function insert(value){
			// 	return {into:function(array){
			// 		return {after:function(afterValue){
			// 			array.splice(array.indexOf(afterValue) + 1,0,value);
			// 			return array;
			// 		}};
			// 	}};
			// }
			// console.log(insert(2).into([1,3]).after(1));//[1,2,3]

			// let insert = (value) =>({into:(array) =>({after:(afterValue) =>{array.splice(array.indexOf(afterValue) + 1,0,value);
			// 			return array;}})})
			// console.log(insert(2).into([1,3]).after(1));//[1,2,3]


			// const pipeline = (...funcs) =>
			// 	val => funcs.reduce((a,b) => b(a),val);
			// const plus1 = a => a+1;
			// const mult2  = a => a*2;
			// const addThenMult = pipeline(plus1,mult2 );
			// console.log(addThenMult(5));//12

			// const plus1 = a => a+1;
			// const mult2 = a => a*2;
			// console.log(mult2(plus1(5)));//12

			// fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))

			// var fix = f =>(x =>f(v =>x(x)(v)))(x => f(v => x(x)(v)))

			
			// foo::bar;


			// function f(x){
			// 	return g(x);
			// }

			// function f(x){
			// 	let y = g(x);
			// 	return y;
			// }

			// function f(x){
			// 	return g(x)+1;
			// }

			// function f(x){
			// 	g(x);
			// }

			// function f(x){
			// 	g(x);
			// 	return undefined;
			// }

			// function f(x){
			// 	if(x>0){
			// 		return m(x);
			// 	}
			// 	return n(x);
			// }

			// function f(){
			// 	let m = 1;
			// 	let n = 2;
			// 	return g(m+n);
			// }
			// f();

			// function f(){
			// 	return g(3);
			// }

			// f();

			// g(3);

			// function addOne(a){
			// 	var one = 1;
			// 	function inner(b){
			// 		return b+one;
			// 	}
			// 	return inner(a);
			// }

			// function factorial(n){
			// 	if(n===1) return 1;
			// 	return n *factorial(n-1);
			// }

			// console.log(factorial(5));

			// function factorial(n,total){
			// 	if(n === 1) return total;
			// 	return factorial(n-1,n*total);
			// }
			// console.log(factorial(5,1));

			





















			



			









		</script>
	</body>
</html>